local newt = reload("newt")
local delt = reload("delt")
local class = reload("class")
local super = reload("super.database")
local clear = reload("table.opt.clear")
local ctype = reload("enum.clickhouse")
local clickHouseC = require("clickHouseC")
local caches = reload("global.caches")

local treply = {
    select = 1,
}

---@class clickHouseLC : database @clickhouse
local this = class(super)

function this:ctor(name, info)
    super.ctor(self)
    self._name = name
    self._info = info
end

function this:launch()
    super.launch(self)
    local info = self._info
    clickHouseC.new(
        self._name,
        info.ip,
        info.port,
        info.db,
        info.user,
        info.password,
        self)
    return self:hand()
end

function this:callback(cookid)
    clickHouseC.callback(cookid)
end

function this:decode(ireply, info, ...)
    if ireply == treply.select then
        self:selectpush(info.args, ...)
    else
        self:nonepush(info.args, ...)
    end
end

function this:type()
    return ctype
end

function this:select(sql)
    local cook = self:cook()
    clickHouseC.select(cook, self._name, sql)
    return self:watch(treply.select)
end

local colList = {}
function this:insertBlock(tname, fields, rows)
    assert(self._info.write or false, "没有写入权限")
    local cook = self:cook()
    clickHouseC.cblock()
    for colName, colType in pairs(fields) do
        clear(colList)
        for i, row in ipairs(rows) do
            table.insert(colList, row[colName])
        end
        clickHouseC.column(colName, colType, colList)
    end
    clickHouseC.insertBlock(cook, self._name, tname)
    return self:watch(false)
end

function this:insertRow(tname, rows)
    assert(self._info.write or false, "没有写入权限")
    ---先改成列结构
    local fields = self:getFields(tname)
    return self:insertBlock(tname, fields, rows)
end

function this:insertOne(tname, row)
    assert(self._info.write or false, "没有写入权限")
    local rows = newt()
    table.insert(rows, row)
    local watch = self:insertRow(tname, rows)
    delt(rows)
    return watch
end

function this:update(sql, ...)
    assert(self._info.write or false, "没有写入权限")
    local cook = self:cook()
    clickHouseC.update(cook, self._name, sql, ...)
    return self:watch(false)
end

function this:delete(sql)
    assert(self._info.write or false, "没有写入权限")
    local cook = self:cook()
    clickHouseC.delete(cook, self._name, sql)
    return self:watch(false)
end

function this:create(sql)
    assert(self._info.write or false, "没有写入权限")
    local cook = self:cook()
    clickHouseC.create(cook, self._name, sql)
    return self:watch(false)
end

function this:drop(sql)
    assert(self._info.write or false, "没有写入权限")
    local cook = self:cook()
    clickHouseC.drop(cook, self._name, sql)
    return self:watch(false)
end

function this:alter(sql)
    assert(self._info.write or false, "没有写入权限")
    local cook = self:cook()
    clickHouseC.alter(cook, self._name, sql)
    return self:watch(false)
end

function this:truncate(sql)
    assert(self._info.write or false, "没有写入权限")
    local cook = self:cook()
    clickHouseC.truncate(cook, self._name, sql)
    return self:watch(false)
end

function this:explain(sql)
    assert(self._info.write or false, "没有写入权限")
    local cook = self:cook()
    clickHouseC.explain(cook, self._name, sql)
    return self:watch(false)
end

function this:show(sql)
    local cook = self:cook()
    clickHouseC.show(cook, self._name, sql)
    return self:watch(false)
end

function this:use(sql)
    local cook = self:cook()
    clickHouseC.use(cook, self._name, sql)
    return self:watch(false)
end

function this:await(carg)
    local sql = "show databases;"
    self:show(sql)(self.coback, self, carg)
    super.await(self, carg)
end

---获取字段类型
function this:getFields(tname)
    local map = caches.clickhouseFields or {}
    caches.clickhouseFields = map
    local fields = map[tname]
    return fields
end

---记录字段数量
function this:setFields(tname, fields)
    local map = caches.clickhouseFields or {}
    caches.clickhouseFields = map
    map[tname] = fields
end

return this
